package com.icesoft.framework.core.util;

import lombok.NonNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * Map 类增强
 */
@SuppressWarnings("unused")
public class MapUtil {

	public static <K, V> boolean isNotEmpty(Map<K, V> map) {
		return !Objects.isNull(map) && !map.isEmpty();
	}

	public static <K, V> boolean isEmpty(Map<K, V> map) {
		return Objects.isNull(map) || map.isEmpty();
	}

	/**
	 * list 转 Map 自定义转换
	 *
	 * <p> List<Student> list = Arrays.as(
	 * <pre>
	 * Student.newBuilder().id(1).name("A").clazz("一班").build(),
	 * Student.newBuilder().id(2).name("B").clazz("一班").build(),
	 * Student.newBuilder().id(3).name("C").clazz("二班").build()</pre>
	 * );
	 * </p>
	 *
	 * <p> Map<Integer, Student> map = format(list, Student::getId);</p>
	 * <pre>
	 * 1:{"id":1,"name":"A","clazz":"一班"},
	 * 2:{"id":2,"name":"B","clazz":"一班"},
	 * 3:{"id":3,"name":"C","clazz":"二班"}
	 * </pre>
	 *
	 * @param list    数据
	 * @param keyFunc key转换函数
	 * @param <T>     数据源类型
	 * @param <K>     key类型
	 * @return Map<K, T>
	 */
	public static <T, K> Map<K, T> format(List<T> list, @NonNull Function<T, K> keyFunc) {
		return format(list, keyFunc, t -> t);
	}

	/**
	 * 自定义转换
	 *
	 * <p> List<Student> list = Arrays.as(
	 * <pre>
	 * Student.newBuilder().id(1).name("A").clazz("一班").build(),
	 * Student.newBuilder().id(2).name("B").clazz("一班").build(),
	 * Student.newBuilder().id(3).name("C").clazz("二班").build()</pre>
	 * );
	 * </p>
	 *
	 * <p> Map<Integer, Student> map = format(list, Student::getId,Student::getName);</p>
	 * <pre> 1:"A",2:"B",3:"C"</pre>
	 *
	 * @param list    数据
	 * @param keyFunc key转换函数
	 * @param valFunc 值转换函数
	 * @param <T>     数据源类型
	 * @param <K>     key类型
	 * @param <V>     值类型
	 * @return Map<K, V>
	 */
	public static <T, K, V> Map<K, V> format(List<T> list, @NonNull Function<T, K> keyFunc, @NonNull Function<T, V> valFunc) {
		Map<K, V> map = new ConcurrentHashMap<>();
		if (ListUtil.isNotEmpty(list)) {
			for (T t : list) {
				map.put(keyFunc.apply(t), valFunc.apply(t));
			}
		}
		return map;
	}

	/**
	 * List转MapList
	 * <p>示例：
	 * <pre>
	 * [{"id":1,"name":"A","clazz":"一班"},
	 * {"id":2,"name":"B","clazz":"一班"},
	 * {"id":3,"name":"C","clazz":"二班"}]</pre>
	 * </p>
	 *
	 * <p> Map<Integer, List<Student>> map = format(list, Student::getClazz);</p>
	 * <p>转为：
	 * <pre>
	 * "一班"=[{"id":1,"name":"A","clazz":"一班"},{"id":2,"name":"B","clazz":"一班"}]
	 * "二班"=[{"id":3,"name":"C","clazz":"二班"}]</pre>
	 * </p>
	 *
	 * @param list    源数据
	 * @param keyFunc key方法
	 * @return Map<K, List < T>>
	 */
	public static <T, K> Map<K, List<T>> format2List(List<T> list, @NonNull Function<T, K> keyFunc) {
		return format2List(list, keyFunc, t -> t);
	}

	/**
	 * List转MapList
	 * <p>示例：
	 * <pre>
	 * [{"id":1,"name":"A","clazz":"一班"},
	 * {"id":2,"name":"B","clazz":"一班"},
	 * {"id":3,"name":"C","clazz":"二班"}]</pre>
	 * </p>
	 *
	 * <p> Map<Integer, List<Student>> map = format(list, Student::getClazz, Student::getName);</p>
	 * <p>转为：
	 * <pre>
	 * "一班"=["A","B"]
	 * "二班"=["C"]</pre>
	 * </p>
	 *
	 * @param list    源数据
	 * @param keyFunc key方法
	 * @return Map<K, List < T>>
	 */
	public static <T, K, V> Map<K, List<V>> format2List(List<T> list, @NonNull Function<T, K> keyFunc, @NonNull Function<T, V> valFunc) {
		Map<K, List<V>> map = new ConcurrentHashMap<>();
		if (ListUtil.isNotEmpty(list)) {
			for (T t : list) {
				put(map, keyFunc.apply(t), valFunc.apply(t));
			}
		}
		return map;
	}

	/**
	 * 向map中填充List数据 判断null并主动添加空集合
	 *
	 * @param map map对象
	 * @param key key
	 * @param t   数据
	 * @param <T> 源数据类型
	 * @param <K> map-key类型
	 */
	public static <T, K> void put(Map<K, List<T>> map, K key, T t) {
		if (!Objects.isNull(key)) {
			if (Objects.isNull(map)) {
				map = new ConcurrentHashMap<>();
			}
			if (Objects.isNull(map.get(key))) {
				map.put(key, new ArrayList<>());
			}
			if (!Objects.isNull(t)) {
				map.get(key).add(t);
			}
		}
	}

	public static void put(Map<String, List<String>> map, String key, String t) {
		if (!Objects.isNull(key)) {
			if (Objects.isNull(map)) {
				map = new ConcurrentHashMap<>();
			}
			if (Objects.isNull(map.get(key))) {
				map.put(key, new ArrayList<>());
			}
			if (!Objects.isNull(t)) {
				map.get(key).add(t);
			}
		}
	}

	public static <T, R> Map<T, R> asMap(T key, R val) {
		Map<T, R> map = new ConcurrentHashMap<>();
		map.put(key, val);
		return map;
	}

	@SafeVarargs
	public static <T> Map<T, T> asMap(T[]... entryArr) {
		Map<T, T> map = new ConcurrentHashMap<>();
		for (T[] entry : entryArr) {
			if (entry.length == 2) {
				map.put(entry[0], entry[1]);
			}
		}
		return map;
	}

	/**
	 * 忽略key大小写，兼容多库等场景
	 */
	public static <T> T getIgnoreCase(Map<String, T> map, String key) {
		if (map.containsKey(key)) {
			return map.get(key);
		}
		if (map.containsKey(key.toUpperCase())) {
			return map.get(key.toUpperCase());
		}
		return map.get(key.toLowerCase());
	}
}
